package com.asialjim.wechat.apiservice;

import com.asialjim.wechat.utils.JsonUtils;
import com.asialjim.wechat.utils.MapUtils;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.*;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.Map;
import java.util.Objects;

/**
 * <h1><em>ASIAL JIM JAVA DOC</em></h1><hr/>
 * <h2>CLASS DESCRIPTION <i>[ NAME: com.asialjim.wechat.api.HttpMethod ]</i></h2><strong>
 * <p> HTTP METHOD for TENCENT WE-CHAT API same as org.springframework.http.HttpMethod
 * </strong><p><p><em>Copyright &copy; Asial Jim Co., LTD</em><hr/>
 *
 * @author Asial Jim &nbsp;&nbsp; <span>Email:<a href="mailto:asialjim@hotmail.com">asialjim@hotmail.com</a> &nbsp;&nbsp; <a href="asialjim@qq.com">asialjim@qq.com</a></span>
 * @version 1.0.0
 * @since 2021/3/1   &nbsp;&nbsp; JDK 8
 */
@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public enum HttpMethod {

    /**
     * <h3>FIELD DESCRIPTION</h3>
     * get
     */
    GET("get"){
        @Override
        protected HttpRequestBase doCreateHttpRequest(String url, ApiRequest.RequestBodyParam bodyParam) {
            return new HttpGet(url);
        }
    },

    /**
     * <h3>FIELD DESCRIPTION</h3>
     * head
     */
    HEAD("head"){
        @Override
        protected HttpRequestBase doCreateHttpRequest(String url, ApiRequest.RequestBodyParam bodyParam) {
            return new HttpHead(url);
        }
    },

    /**
     * <h3>FIELD DESCRIPTION</h3>
     * post
     */
    POST("post"){
        @Override
        protected HttpRequestBase doCreateHttpRequest(String url, ApiRequest.RequestBodyParam bodyParam) {
            HttpPost httpPost = new HttpPost(url);
            log.info("\r\n\tCREATE POST METHOD HTTP REQUEST--URL:[{}]",url);
            if (Objects.isNull(bodyParam)){
                return httpPost;
            }

            if (Objects.nonNull(bodyParam.file())){
                HttpEntity entity = MultipartEntityBuilder.create().addBinaryBody(bodyParam.uploadFileName(),bodyParam.file()).setMode(HttpMultipartMode.RFC6532).build();
                httpPost.setEntity(entity);
                return httpPost;
            }

            String bodyString = JsonUtils.toJson(bodyParam);
            assert bodyString != null;
//            Map<String, Object> bodyMap = JsonUtils.jsonToMap(bodyString);
//            if (Objects.nonNull(bodyMap)){
//                bodyMap =  MapUtils.cleanNullValue(bodyMap);
//                log.warn("\r\n\tCREATE POST METHOD HTTP REQUEST--ENTITY-MAP:[{}]",JsonUtils.toJson(bodyMap));
//            }

            log.info("\r\n\tCREATE POST METHOD HTTP REQUEST--ENTITY:[{}]",bodyString);
            StringEntity entity = new StringEntity(bodyString, Consts.UTF_8);
            entity.setContentType("application/json; charset=utf-8");
            httpPost.setEntity(entity);
            log.info("\r\n\tCREATE POST METHOD HTTP REQUEST CLIENT RESULT:[{}]",httpPost);
            return httpPost;
        }
    },

    /**
     * <h3>FIELD DESCRIPTION</h3>
     * put
     */
    PUT("put"){
        @Override
        protected HttpRequestBase doCreateHttpRequest(String url, ApiRequest.RequestBodyParam bodyParam) {
            // TODO
            return new HttpPut(url);
        }
    },

    /**
     * <h3>FIELD DESCRIPTION</h3>
     * patch
     */
    PATCH("patch"){
        @Override
        protected HttpRequestBase doCreateHttpRequest(String url, ApiRequest.RequestBodyParam bodyParam) {
            // TODO
            return new HttpPatch(url);
        }
    },

    /**
     * <h3>FIELD DESCRIPTION</h3>
     * delete
     */
    DELETE("delete"){
        @Override
        protected HttpRequestBase doCreateHttpRequest(String url, ApiRequest.RequestBodyParam bodyParam) {
            // TODO
            return new HttpDelete(url);
        }
    },

    /**
     * <h3>FIELD DESCRIPTION</h3>
     * options
     */
    OPTIONS("options"){
        @Override
        protected HttpRequestBase doCreateHttpRequest(String url, ApiRequest.RequestBodyParam bodyParam) {
            // TODO
            return new HttpOptions(url);
        }
    },

    /**
     * <h3>FIELD DESCRIPTION</h3>
     * trace
     */
    TRACE("trace"){
        @Override
        protected HttpRequestBase doCreateHttpRequest(String url, ApiRequest.RequestBodyParam bodyParam) {
            // TODO
            return new HttpTrace(url);
        }
    };

    /**
     * <h3>FIELD DESCRIPTION</h3>
     * name of http method
     */
    private final String name;
    private static final String ACCESS_TOKEN_PARAM_TEMPLATE = "access_token=%s";
    private static final Logger log = LoggerFactory.getLogger(HttpMethod.class);

    /**
     * <h3>METHOD DESCRIPTION <i>[ NAME: nameOf ]</i></h3>
     * get http method by name
     * @param name {@link String name of method}
     * @return {@link HttpMethod http method}
     * @author Asial Jim &nbsp;&nbsp;<span>Email:asialjim@hotmail.com &nbsp;&nbsp; asialjim@qq.com</span>
     * @since 2021/3/2 9:53
     */
    public static HttpMethod nameOf(String name){
        return Arrays.stream(values()).filter(value -> value.match(name)).findFirst().orElse(null);
    }

    /**
     * <h3>METHOD DESCRIPTION <i>[ NAME: match ]</i></h3>
     * the name is match the current method
     * @param name {@link String name}
     * @return {@link Boolean is match }
     * @author Asial Jim &nbsp;&nbsp;<span>Email:asialjim@hotmail.com &nbsp;&nbsp; asialjim@qq.com</span>
     * @since 2021/3/2 9:54
     */
    public boolean match(String name){
        return this.getName().equals(name.toLowerCase());
    }

    /**
     * <h3>METHOD DESCRIPTION <i>[ NAME: createHttpRequest ]</i></h3>
     * create http request
     * @param url {@link String request url}
     * @param urlParam {@link ApiRequest.RequestUrlParam url param}
     * @param bodyParam {@link ApiRequest.RequestBodyParam body param}
     * @return {@link org.apache.http.client.methods.HttpRequestBase http request}
     * @author Asial Jim &nbsp;&nbsp;<span>Email:asialjim@hotmail.com &nbsp;&nbsp; asialjim@qq.com</span>
     * @since 2021/3/2 9:55
     */
    public HttpRequestBase createHttpRequest(String url, ApiRequest.RequestUrlParam urlParam, ApiRequest.RequestBodyParam bodyParam){
        if (Objects.nonNull(urlParam)) {
            Map<String, Object> urlParamMap = JsonUtils.objectToMap(urlParam);
            for (Map.Entry<String, Object> entry : urlParamMap.entrySet()) {
                String source = entry.getKey() + "=%s";
                String target = String.format(source,entry.getValue());
                url = url.replaceAll(source,target);
            }
        }
        return doCreateHttpRequest(url,bodyParam);
    }

    /**
     * <h3>METHOD DESCRIPTION <i>[ NAME: createHttpRequest ]</i></h3>
     * create http request
     * @param url {@link String request url}
     * @param urlParam {@link ApiRequest.RequestUrlParam url param}
     * @param bodyParam {@link ApiRequest.RequestBodyParam body param}
     * @return {@link org.apache.http.client.methods.HttpRequestBase http request}
     * @author Asial Jim &nbsp;&nbsp;<span>Email:asialjim@hotmail.com &nbsp;&nbsp; asialjim@qq.com</span>
     * @since 2021/3/2 9:55
     */
    public HttpRequestBase createHttpRequest(String url, Map<String,Object> urlParam, ApiRequest.RequestBodyParam bodyParam){
        if (Objects.nonNull(urlParam)) {
            for (Map.Entry<String, Object> entry :urlParam.entrySet()) {
                String source = entry.getKey() + "=%s";
                String target = String.format(source,entry.getValue());
                url = url.replaceAll(source,target);
            }
        }
        return doCreateHttpRequest(url,bodyParam);
    }

    /**
     * <h3>METHOD DESCRIPTION <i>[ NAME: doCreateHttpRequest ]</i></h3>
     * the real method for create http request
     * @return {@link org.apache.http.client.methods.HttpRequestBase http request}
     * @author Asial Jim &nbsp;&nbsp;<span>Email:asialjim@hotmail.com &nbsp;&nbsp; asialjim@qq.com</span>
     * @since 2021/3/2 9:56
     */
    protected abstract HttpRequestBase doCreateHttpRequest(String url,ApiRequest.RequestBodyParam bodyParam);
}